/*
 * Copyright 2002-2004 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 

package org.springframework.aop.framework;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 创建动态代理的配置信息有
 * 1. 是否子类的形式创建代理proxyTargetClass
 * 2. 代理创建之后,通知链还能修改吗?
 * 3. 是否把代理对象暴露出去给外部使用
 * 4. 是否优化等
 * Convenience superclass for configuration used in creating proxies,
 * to ensure that all proxy creators have consistent properties.
 * <br>
 * Note that it is no longer possible to configure subclasses to
 * expose the MethodInvocation. Interceptors should normally manage their own
 * ThreadLocals if they need to make resources available to advised objects.
 * If it's absolutely necessary to expose the MethodInvocation, use an
 * interceptor to do so.(TODO:这段话写例子阐述)
 *
 * @author Rod Johnson
 * @version $Id: ProxyConfig.java,v 1.9 2004/03/18 02:46:05 trisberg Exp $
 */
public class ProxyConfig {
	
	/*
	 * Note that some of the instance variables in this class and AdvisedSupport
	 * are protected, rather than private, as is usually preferred in Spring
	 * (following "Expert One-on-One J2EE Design and Development", Chapter 4).
	 * This allows direct field access in the AopProxy implementations, which
	 * produces a 10-20% reduction in AOP performance overhead compared with method
	 * access. - RJ, December 10, 2003.
	 */
	
	protected final Log logger = LogFactory.getLog(getClass());

  /** 是否直接代理类,如果设置为true就不管target是否有实现接口,会强制使用cglib生成代理类,默认值是false*/
  private boolean proxyTargetClass;
	
	private boolean optimize;
	
	/**
	 * Is this config frozen: that is, should it be impossible
	 * to change advice. Default is not frozen.
	 */
	private boolean frozen;
	
	/** Factory used to create AopProxy's. */
	private AopProxyFactory aopProxyFactory = new DefaultAopProxyFactory();


  /**是否把生成的代理对象暴露给AopContext,默认是不暴露,因为会伤害(impair)性能
   * Should proxies obtained from this configuration expose
   * the AOP proxy for the AopContext class to retrieve for targets?
   * The default is false, as enabling this property may
   * impair performance.
	 */
	protected boolean exposeProxy;

	
	public ProxyConfig() {
	}

	/**
	 * Copy configuration from the other config
	 * @param other object to copy configuration from
	 */
	public void copyFrom(ProxyConfig other) {
		this.optimize = other.getOptimize();
		this.proxyTargetClass = other.proxyTargetClass;
		this.exposeProxy = other.exposeProxy;
		this.frozen = other.frozen;
		this.aopProxyFactory = other.aopProxyFactory;
	}

	public boolean getProxyTargetClass() {
		return this.proxyTargetClass;
	}

	/**
	 * Set whether to proxy the target class directly as well as any interfaces.
	 * We can set this to true to force CGLIB proxying. Default is false
	 * @param proxyTargetClass whether to proxy the target class directly as well as any interfaces
	 */
	public void setProxyTargetClass(boolean proxyTargetClass) {
		this.proxyTargetClass = proxyTargetClass;
	}
	
	/**
	 * @return whether proxies should perform agressive optimizations.
	 */
	public boolean getOptimize() {
		return this.optimize;
  }

  /**
   * 设置代理是否应该执行主动优化。“主动优化”的确切含义在代理之间是不同的，但通常会有一些折衷。
   * 例如，优化通常意味着在创建代理后就不允许修改通知链。
   * 因此，为了允许修改通知链,默认情况下禁用优化。
   * 如果其他设置排除了优化，则优化值为true可能会被忽略而不优化:
   * 例如，如果exposeProxy被设置为true，而这与优化不兼容所以不会优化。
   *
   * 例如，cglib增强的代理可能会进行优化。会覆盖方法而不使用通知链。这样就没有递归调用
   * 对于没有通知的方法，因为所有的代码都合并在一起了，这可以提高2.5倍的性能。
   * 警告:当使用CGLIB时，将此设置为true会产生很大的性能提升(也将proxyTargetClass设置为true)，
   * 所以对于性能关键的代理来说，这是一个很好的设置。但是，启用此功能将意味着在从该工厂获得代理后不能更改通知
   * Set whether proxies should perform agressive optimizations.
   * The exact meaning of "agressive optimizations" will differ
   * between proxies, but there is usually some tradeoff.
   * For example, optimization will usually mean that advice changes won't take
   * effect after a proxy has been created. For this reason, optimization
   * is disabled by default. An optimize value of true may be ignored
   * if other settings preclude optimization: for example, if exposeProxy
   * is set to true and that's not compatible with the optimization.
   * <br>For example, CGLIB-enhanced proxies may optimize out.
   * overriding methods with no advice chain. This can produce 2.5x performance
   * improvement for methods with no advice.
   * <br><b>Warning:</b> Setting this to true can produce large performance
   * gains when using CGLIB (also set proxyTargetClass to true), so it's
   * a good setting for performance-critical proxies. However, enabling this
   * will mean that advice cannot be changed after a proxy has been obtained
   * from this factory.
   * @param optimize whether to enable agressive optimizations.
   * Default is false.
   */
  public void setOptimize(boolean optimize) {
    this.optimize = optimize;
  }


	/**
	 * @return whether the AOP proxy will expose the AOP proxy for
	 * each invocation.
	 */
	public final boolean getExposeProxy() {
		return this.exposeProxy;
  }

  /**
   * Set whether the proxy should be exposed by the AOP framework as a ThreadLocal for
   * retrieval via the AopContext class. This is useful if an advised object needs
   * to call another advised method on itself. (If it uses <code>this</code>, the invocation
   * will not be advised)(因为目标对象间的方法间调用,被调用方法的执行逻辑是没有被代理的逻辑,
   * 用this调用其它方法执行的原本方法的逻辑,而不是执行被代理后的逻辑).
   * @param exposeProxy whether the proxy should be exposed. Default
   * is false, for optimal performance.
	 */
	public final void setExposeProxy(boolean exposeProxy) {
		this.exposeProxy = exposeProxy;
	}
	
	
	/**
	 * Customise the AopProxyFactory, allowing different strategies
	 * to be dropped in without changing the core framework.
	 * For example, an AopProxyFactory could return an AopProxy using
	 * dynamic proxies, CGLIB or code generation strategy. 
	 * @param apf AopProxyFactory to use. The default uses dynamic
	 * proxies or CGLIB.
	 */
	public void setAopProxyFactory(AopProxyFactory apf) {
		this.aopProxyFactory = apf;
	}
	
	public AopProxyFactory getAopProxyFactory() {
		return this.aopProxyFactory;
	}
	

	/**
	 * @return whether the config is frozen, and no
	 * advice changes can be made
	 */
	public boolean isFrozen() {
		return frozen;
	}

	/**
	 * Set whether this config should be frozen.
	 * When a config is frozen, no advice changes can be
	 * made. This is useful for optimization, and useful
	 * when we don't want callers to be able to manipulate
	 * configuration after casting to Advised.
	 * @param frozen is this config frozen?
	 */
	public void setFrozen(boolean frozen) {
		this.frozen = frozen;
	}
	
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("exposeProxy=" + exposeProxy + "; ");
		sb.append("frozen=" + frozen + "; ");
		sb.append("enableCglibSubclassOptimizations=" + optimize + "; ");
		sb.append("aopProxyFactory=" + aopProxyFactory + "; ");
		return sb.toString();
	}

}
